package com.study.living.camera;

import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.Surface;
import android.view.TextureView;

import androidx.annotation.NonNull;

public class TexturePreview {
    private static final String TAG = "Camera2";

    private final AutoFitTextureView mTextureView;

    /** This is either Surface.Rotation_0, _90, _180, _270, or -1 (invalid). */
    private int mLastRotation = -1;

    static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray();

    static {
        DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0);
        DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90);
        DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180);
        DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270);
    }

    private int mWidth;
    private int mHeight;

    private OnSurfaceAvailableListener mOnSurfaceAvailableListener;

    public TexturePreview(AutoFitTextureView textureView) {
        mTextureView = textureView;
        mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                Log.i(TAG, "onSurfaceTextureAvailable: " + width + "-" + height);
                setSize(width, height);
                configureTransform();
                if (mOnSurfaceAvailableListener != null){
                    mOnSurfaceAvailableListener.onSurfaceAvailable();
                }
            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
                Log.i(TAG, "onSurfaceTextureSizeChanged: " + width + "-" + height);
                setSize(width, height);
                configureTransform();
            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                Log.i(TAG, "onSurfaceTextureDestroyed: " + surface.toString());
                setSize(0, 0);
                if (mOnSurfaceAvailableListener != null){
                    mOnSurfaceAvailableListener.onSurfaceDestroyed();
                }
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
            }
        });
    }

    private void setSize(int width, int height) {
        mWidth = width;
        mHeight = height;
    }

    /**
     * Configures the transform matrix for TextureView based on rotation and
     * the surface size.
     */
    private void configureTransform() {
        int displayOrientation = -1;
        Display display = mTextureView.getDisplay();
        if (display != null){
            int rotation = display.getRotation();
            if (mLastRotation != rotation){
                mLastRotation = rotation;
                displayOrientation = DISPLAY_ORIENTATIONS.get(mLastRotation);
                Log.i(TAG, "configureTransform: " + displayOrientation);
            }
        }

        if (displayOrientation == -1){
            return;
        }


        Matrix matrix = new Matrix();
        if (displayOrientation % 180 == 90) {
            final int width = getWidth();
            final int height = getHeight();
            // Rotate the camera preview when the screen is landscape.
            matrix.setPolyToPoly(
                    new float[]{
                            0.f, 0.f, // top left
                            width, 0.f, // top right
                            0.f, height, // bottom left
                            width, height, // bottom right
                    }, 0,
                    displayOrientation == 90 ?
                            // Clockwise
                            new float[]{
                                    0.f, height, // top left
                                    0.f, 0.f, // top right
                                    width, height, // bottom left
                                    width, 0.f, // bottom right
                            } : // displayOrientation == 270
                            // Counter-clockwise
                            new float[]{
                                    width, 0.f, // top left
                                    width, height, // top right
                                    0.f, 0.f, // bottom left
                                    0.f, height, // bottom right
                            }, 0,
                    4);
        } else if (displayOrientation == 180) {
            matrix.postRotate(180, getWidth() / 2, getHeight() / 2);
        }
        mTextureView.setTransform(matrix);
    }

    public Surface getSurface() {
        return new Surface(mTextureView.getSurfaceTexture());
    }

    public boolean isReady() {
        return mTextureView.getSurfaceTexture() != null;
    }

    public int getWidth() {
        return mWidth;
    }

    public int getHeight() {
        return mHeight;
    }

    // This method is called only from Camera2.
    public void setBufferSize(int width, int height) {
        mTextureView.setAspectRatio(width, height);
    }

    public void setOnSurfaceAvailableListener(OnSurfaceAvailableListener onSurfaceAvailableListener){
        mOnSurfaceAvailableListener = onSurfaceAvailableListener;
    }

    public interface OnSurfaceAvailableListener{
        void onSurfaceAvailable();
        void onSurfaceDestroyed();
    }
}
